#include "Game.h"
#include "Size.h"
#include "Level1.h"
//#include "MainMenu.h"
#include "PublisherScene.h"
#include "GLUtils.h"
#include "AudioManager.h"
#include "Logger.h"
#include "GameOptions.h"

using namespace game_engine;
using namespace game_engine::open_gl;
using namespace game_engine::utils;

bool Game::instanceFlag = false;
Game* Game::instance = NULL;

Scene* Game::currentScene = NULL;
GameOptions Game::_gameOptions;

///////////////////////////////////////////////////////////////////////////////
// Constructors and Destructors
///////////////////////////////////////////////////////////////////////////////

Game::~Game(void)
{
    instanceFlag = false;
}

///////////////////////////////////////////////////////////////////////////////
// Other public methods
///////////////////////////////////////////////////////////////////////////////

void Game::init(INT32 argc, char** argv) const throw(...)
{
    // Initialize the graphic framework
    GLUtils::mainInit(argc, argv, "DEMO1", Game::render,
        Game::readKey, Game::readSpecialKey, Game::readKeyUp, 
        Game::readSpecialKeyUp, Game::readMouse, Game::loop);
    
    // Initialize the audio system
    AudioManager *audioManager = AudioManager::getInstance();

    //// Create the main menu and initialize it
    //MainMenu *mainMenu = new MainMenu();
    //mainMenu->setResolution(Size(512, 640));
    //currentScene = mainMenu;
    //currentScene->initialize();

    // Create the publisher scene and initialize it
    PublisherScene *publisherScene = new PublisherScene();
    publisherScene->setResolution(Size(512, 640));
    currentScene = publisherScene;
    currentScene->initialize();

    // Initialize game options
    _gameOptions.setDifficulty(MEDIUM);
    _gameOptions.setGraphicDetail(MODERATE);
    _gameOptions.setMusicEnabled(true);
    _gameOptions.setFxEnabled(true);
}

void Game::run(void) const
{
	// Application loop
	GLUtils::startEventLoop();
}

void Game::loop(void)
{
    try
    {
        Scene *newScene = currentScene->getNextScene();
        if (newScene == NULL)
        {
            currentScene->finalize();
            finalize();
        }
        else if ((newScene != NULL) && (newScene != currentScene))
        {
            // Execute transition
            currentScene->finalize();
            currentScene = newScene;
            currentScene->initialize();
        }
        else
        {
            currentScene->loop();
        }

    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::loop : ") + e.what());
    }
}

void Game::finalize(void)
{
    try
    {
        AudioManager *audioManager = AudioManager::getInstance();
        delete audioManager;
	    //cout << "Press ENTER to close the game ...";
	    //getline(cin, string());
        exit(0);
    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::finalize : ") + e.what());
    }
}

void Game::readKey(const UCHAR key, const INT32 x, const INT32 y)
{
    try
    {
        currentScene->readKeyboard(key, x, y, true);
    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::readKeyboard : ") + e.what());
    }
}

void Game::readSpecialKey(const INT32 key, const INT32 x, const INT32 y)
{
    try
    {
        currentScene->readKeyboard(static_cast<UCHAR>(key), x, y, true);
    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::readSpecialKey : ") + e.what());
    }
}

void Game::readKeyUp(const UCHAR key, const INT32 x, const INT32 y)
{
    try
    {
        currentScene->readKeyboard(key, x, y, false);
    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::readKeyUp : ") + e.what());
    }
}

void Game::readSpecialKeyUp(const INT32 key, const INT32 x, const INT32 y)
{
    try
    {
        currentScene->readKeyboard(static_cast<UCHAR>(key), x, y, false);
    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::readSpecialKeyUp : ") + e.what());
    }
}

void Game::readMouse(const INT32 button, const INT32 state, 
                      const INT32 x, const INT32 y)
{
    try
    {
        currentScene->readMouse(button, state, x, y);
    } catch (exception &e)
    {
        cout << "exception in Game::readMouse : " << e.what();
    }
}

void Game::render(void)
{
    try
    {
        currentScene->render();
    } catch (exception &e)
    {
        Logger::FATAL(GAME_LOG, string("exception in Game::render : ") + e.what());
    }
}

///////////////////////////////////////////////////////////////////////////////
// Private methods
///////////////////////////////////////////////////////////////////////////////

Game::Game(void)
{
}

///////////////////////////////////////////////////////////////////////////////
// Getters
///////////////////////////////////////////////////////////////////////////////

Game* Game::getInstance(void)
{
    if(!instanceFlag)
    {
        instance = new Game();
        instanceFlag = true;
        return instance;
    }
    else
    {
        return instance;
    }
}

GameOptions Game::gameOptions(void)
{
    return _gameOptions;
}

///////////////////////////////////////////////////////////////////////////////
// Setters
///////////////////////////////////////////////////////////////////////////////

void Game::setGameOptions(const GameOptions &gameOptions)
{
    //_gameOptions.setDifficulty(gameOptions.difficulty());
    //_gameOptions.setGraphicDetail(gameOptions.graphicDetail());
    //_gameOptions.setMusicEnabled(gameOptions.isMusicEnabled());
    //_gameOptions.setFxEnabled(gameOptions.isFxEnabled());
    _gameOptions = gameOptions;
}